package com.lcredu.springboot.config;

import com.lcredu.springboot.entity.Cat;
import com.lcredu.springboot.entity.Dog;
import com.lcredu.springboot.entity.Furn;
import com.lcredu.springboot.entity.Monster;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Scope;

/**
 * @author 黎长容
 * @date 2025-08-09 18:15
 */

/**
 * 配置类，用于定义和配置应用程序中的Bean对象
 * 1. proxyBeanMethods：代理 bean 的方法
 * (1) Full(proxyBeanMethods = true)、【保证每个@Bean 方法被调用多少次返回的组件都是单实例的, 是代理方式】
 * (2) Lite(proxyBeanMethods = false)【每个@Bean 方法被调用多少次返回的组件都是新创建的, 是非代理方式】
 * (3) 特别说明: proxyBeanMethods 是在 调用@Bean 方法 才生效，因此，需要先获取
 * BeanConfig 组件，再调用方法
 * * 而不是直接通过 SpringBoot 主程序得到的容器来获取 bean, 注意观察直接通过
 * ioc.getBean() 获取 Bean, proxyBeanMethods 值并没有生效
 * (4) 如何选择: 组件依赖必须使用 Full 模式默认。如果不需要组件依赖使用 Lite 模
 * (5) Lite 模 也称为轻量级模式，因为不检测依赖关系，运行速度快
 */

/**
 * 导入Cat和Dog类到当前配置中
 * <p>
 * 该注解用于将指定的类导入到Spring配置中，使得这些类可以被容器管理和注入。
 * 默认ID值为: 类的全限定名(com.lcredu.springboot.entity.Cat)
 * 导入的类包括：
 * - Cat.class: 猫类
 * - Dog.class: 狗类
 */
//@Import({Cat.class, Dog.class})
/**
 * 启用配置属性功能，将Furn类作为配置属性源进行注册
 * 该注解用于启用Spring Boot的配置属性功能，并将指定的类（Furn.class）注册为配置属性源。
 * 这样Furn类中的属性就可以通过application.properties或application.yml文件进行配置。
 * 注意：Furn类需要使用@ConfigurationProperties注解标记，以指定其属性前缀。
 */
@EnableConfigurationProperties({Furn.class})
@Configuration(proxyBeanMethods = false)
public class BeanConfig {

    /**
     * 创建一个Monster类型的Bean实例
     * 该Bean的作用域为原型模式，每次获取都会创建新的实例
     *
     * @return Monster 返回一个初始化完成的Monster对象，包含ID为1，名称为"牛魔王"，年龄为23，技能为"铁牛拳"
     */
    @Bean("monster02")
//    @Scope("prototype")
    public Monster monster01() {
        return new Monster(1, "牛魔王", 23, "铁牛拳");
    }


//    @Bean(name = "lcr_cat")
    @Bean
    public Cat cat() {
        return new Cat();
    }


/**
 * 创建Dog对象的Bean工厂方法
 * 
 * <p>该方法用于创建并注册Dog类型的Bean到Spring容器中。
 * 使用@ConditionalOnMissingBean注解确保只有在容器中不存在名为"lcr_cat"的Bean时才会创建Dog Bean。
 * 这样可以避免Bean定义冲突，实现条件化的Bean注册。</p>
 * 还可以放在类上,表示这个配置类下面的所有bean都要遵循这个约束
 * 
 * @return Dog 返回新创建的Dog实例
 * 
 * @see org.springframework.context.annotation.Bean
 * @see org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
 */
//    @ConditionalOnBean(name = "lcr_cat")
    @ConditionalOnMissingBean(name = "lcr_cat")
    @Bean
    public Dog dog() {
        return new Dog();
    }


}

